import java.util.Enumeration;
import java.util.List;
import java.util.Vector;

import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;


public class AgentTreeModel extends DefaultTreeModel
{
	protected RootNode m_root;
	private Vector m_listeners;
	
	public AgentTreeModel(RootNode root)
	{
		super(root);
		m_listeners = new Vector<TreeModelListener>();
		m_root = root;
	}

	@Override
	public Object getRoot() {
		return m_root;
	}
	
	public RootNode getRootTreeNode()
	{
		return m_root;
	}

	@Override
	public Object getChild(Object parent, int index) 
	{
		if(parent instanceof RootNode)
		{
			return ((RootNode)parent).getAgents().get(index);
		}
		if(parent instanceof AgentNode)
		{
			return ((AgentNode)parent).getChilds().get(index);
		}
		// The parent is leaf
		return null;
	}

	@Override
	public int getChildCount(Object parent) 
	{
		if(parent instanceof RootNode)
		{
			return ((RootNode)parent).getAgents().size();
		}
		if(parent instanceof AgentNode)
		{
			return ((AgentNode)parent).getChilds().size();
		}
		// The parent is leaf
		return 0;
	}

	@Override
	public boolean isLeaf(Object node) {
		return node instanceof MonitorDataNode;
	}

	@Override
	public void valueForPathChanged(TreePath path, Object newValue) 
	{
		
	}

	@Override
	public int getIndexOfChild(Object parent, Object child) 
	{
		if(parent instanceof RootNode)
		{
			RootNode root = (RootNode)parent;
			return root.getAgents().indexOf(child);
		}
		if(parent instanceof AgentNode)
		{
			AgentNode agent = (AgentNode)parent;
			return agent.getChilds().indexOf(child);
		}
		// MonitorDataNode is a leaf 
		return -1;
	}
	
	public void markAgentAsDown(AgentNode agent)
	{
		agent.setIsAlive(false);
		TreeNode[] treePath = getPathToRoot(m_root);
		fireTreeNodesChanged(new TreeModelEvent(this, treePath));
	}
	
	public AgentNode addAgent(AgentNode agent)
	{
		AgentNode oldAgent = m_root.addAgent(agent);
		TreeNode[] treePath = getPathToRoot(m_root);
		if(oldAgent != null)
		{
			fireTreeNodesChanged(new TreeModelEvent(this, treePath));
		}
		else
		{
			fireTreeStructureChanged(new TreeModelEvent(this, treePath));
		}
		return oldAgent;
	}
	
	public void fireTreeNodesInserted(TreeModelEvent e) {
		Enumeration listenerCount = m_listeners.elements();
		while (listenerCount.hasMoreElements()) {
			TreeModelListener listener = (TreeModelListener) listenerCount.nextElement();
			listener.treeNodesInserted(e);
		}
	}
	
	public void fireTreeNodesRemoved(TreeModelEvent e) {
		Enumeration listenerCount = m_listeners.elements();
		while (listenerCount.hasMoreElements()) {
			TreeModelListener listener = (TreeModelListener) listenerCount.nextElement();
			listener.treeNodesRemoved(e);
		}
	}
	
	public void fireTreeNodesChanged(TreeModelEvent e) {
		Enumeration listenerCount = m_listeners.elements();
		while (listenerCount.hasMoreElements()) {
			TreeModelListener listener = (TreeModelListener) listenerCount.nextElement();
			listener.treeNodesChanged(e);
		}
	}
	
	public void fireTreeStructureChanged(TreeModelEvent e) {
		Enumeration listenerCount = m_listeners.elements();
		while (listenerCount.hasMoreElements()) {
			TreeModelListener listener = (TreeModelListener) listenerCount.nextElement();
			listener.treeStructureChanged(e);
		}
	}

	@Override
	public void addTreeModelListener(TreeModelListener l) {
		if (l != null && !m_listeners.contains(l)) 
		{
			m_listeners.addElement(l);
		}
	}

	@Override
	public void removeTreeModelListener(TreeModelListener l) 
	{
		if(l != null)
		{
			m_listeners.removeElement(l);
		}
		
	}
 

}
